﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Diagnostics;

namespace InvasionWars
{
    public class ClientServerConn
    {
        private TcpClient client;
        private NetworkStream socketStream;
        //private Socket connection;
        private BinaryReader reader;
        private BinaryWriter writer;
        public ServerConnectionState serverConnectionState { get; set; }

        public Player thisPlayer;

        private bool incomingMsgComplete;
        public Zone[] Zones;

        private Thread MessageListener;
        private string incomingChat;
        public bool ChangesRead;

        public int Port
        {
            get
            {
                return port;
            }
        }
        private int port;

        public string ServerName
        {
            get
            {
                return serverName;
            }
        }
        private string serverName;


        public ClientServerConn(string name, int nPort)
        {
            serverConnectionState = ServerConnectionState.NOT_CONNECTED;
            serverName = name;
            port = nPort;
            incomingChat = "";
            incomingMsgComplete = false;
            thisPlayer = new Player();
            Zones = new Zone[5];
            for (int i = 0; i < 5; i++)
                Zones[i] = new Zone(i);

            ChangesRead = true;

        }

        public void Connect()
        {
            try
            {
                client = new TcpClient(serverName, port);
                
                socketStream = client.GetStream();
                reader = new BinaryReader(socketStream);
                writer = new BinaryWriter(socketStream);
                serverConnectionState = ServerConnectionState.CONNECTED;

                MessageListener = new Thread( new ThreadStart(ConstantListener));
                MessageListener.Start();
            }
            catch(Exception any)
            {
                throw any;
            }
        }

        public void ConstantListener()
        {
            NetMessages nMsg;

            while (serverConnectionState == ServerConnectionState.CONNECTED)
            {
                try
                {
                    //playerWriter.Write(NetMessages.CHECK_IN + "");
                    nMsg = (NetMessages)reader.ReadByte();
                    byte[] bMsg = new byte[8];
                    char[] cMsg = new char[16];
                    //this can be increased later if needed.
                    
                    switch (nMsg)
                    {
                        case NetMessages.ARMY_ASSIGN:
                            
                            
                            bMsg[0] = reader.ReadByte();
                            if ((Armies)bMsg[0] == Armies.HUMAN)
                                thisPlayer.Army = Armies.HUMAN;
                            else
                                thisPlayer.Army = Armies.ALIEN;
                            break;
                        case NetMessages.HAND:
                            //get the hand position 
                            
                            //if (!Helpers.IsNumber((char)reader.PeekChar()))
                            //{
                            //    reader.ReadChar();
                            //}
                            cMsg[0] = reader.ReadChar();
                            int handLoc = (int)cMsg[0] -48;

                            //get the card ID
                            bool isNumber = false;
                            char firstChar = (char)reader.PeekChar();
                            do
                            {
                                if (Helpers.IsNumber(firstChar))
                                {
                                    isNumber = true;
                                }
                                else
                                {
                                    firstChar = reader.ReadChar();
                                    
                                }
                                
                            } while (!isNumber);
                            
                            cMsg = reader.ReadChars(4);

                            //convert the 5 characters into a string
                            string cardID = "";
                            cardID += firstChar;
                            foreach (char c in cMsg)
                            {
                                cardID += c;
                            }

                            //set the card ID the 5 character string into a number ID
                            thisPlayer.Hand[handLoc].SetCard(thisPlayer.Army, cardID);
                            Trace.WriteLine("HandCard[" + handLoc + "] = " + cardID + " received by player " + port);
                            break;
                        case NetMessages.ZONE:
                            cMsg[0] = reader.ReadChar();
                            int zoneLoc = (int)cMsg[0] -48;

                            //Human Cards
                            isNumber = false;
                            firstChar = (char)reader.PeekChar();
                            do
                            {
                                if (Helpers.IsNumber(firstChar))
                                {
                                    isNumber = true;
                                }
                                else
                                {
                                    firstChar = reader.ReadChar();
                                }
                                
                            } while (!isNumber);
                            
                            cMsg = reader.ReadChars(4);

                            //convert the 5 characters into a string
                            cardID = "";
                            cardID += firstChar;
                            foreach (char c in cMsg)
                            {
                                cardID += c;
                            }

                            if (cardID == "00000")
                            {
                                //card is null
                                Zones[zoneLoc].HumanSlot = null;
                            }
                            else
                            {
                                Zones[zoneLoc].HumanSlot = new Card();
                                Zones[zoneLoc].HumanSlot.SetCard(Armies.HUMAN, cardID);
                            }
                            //Alien Side
                            isNumber = false;
                            firstChar = (char)reader.PeekChar();
                            do
                            {
                                if (Helpers.IsNumber(firstChar))
                                {
                                    isNumber = true;
                                }
                                else
                                {
                                    firstChar = reader.ReadChar();
                                }
                                
                            } while (!isNumber);
                            
                            cMsg = reader.ReadChars(4);

                            //convert the 5 characters into a string
                            cardID = "";
                            cardID += firstChar;
                            foreach (char c in cMsg)
                            {
                                cardID += c;
                            }

                            if (cardID == "00000")
                            {
                                //card is null
                                Zones[zoneLoc].AlienSlot = null;
                            }
                            else
                            {
                                Zones[zoneLoc].AlienSlot = new Card();
                                Zones[zoneLoc].AlienSlot.SetCard(Armies.ALIEN, cardID);
                            }

                            
                            break;
                        case NetMessages.TURNSTART:

                            break;
                        case NetMessages.UPDATE:

                            break;
                        case NetMessages.CHECK_IN:
                            //acknowledge the client is connected
                            break;
                        case NetMessages.CHAT:
                            //read in the size of the message then read in the message;
                            
                            UInt16 msgSize;
                            //char[] cMsg;
                            string msgString;
                            
                            if (!Helpers.IsNumber((char)reader.PeekChar()))
                            {
                                reader.ReadChar();
                            }
                            cMsg = reader.ReadChars(2);
                            msgString = "" + cMsg[0];
                            msgString += cMsg[1];
                            msgSize = Convert.ToUInt16(msgString);

                            cMsg = reader.ReadChars(msgSize);

                            foreach (char c in cMsg)
                            {
                                incomingChat += c;    
                            }

                            incomingMsgComplete = true;
                            break;
                        case NetMessages.INITIALIZE_COMPLETE:
                            thisPlayer.initializeComplete = true;
                            break;
                        case NetMessages.UPDATE_COMPLETE:
                            ChangesRead = false;
                            break;
                        case NetMessages.TERMINATE:
                            break;
                    }
                }
                catch (IOException ioe)
                {
                    //do nothing

                }
                nMsg = NetMessages.NULL;
            }
            writer.Write((byte)NetMessages.TERMINATE);

            reader.Close();
            writer.Close();
            socketStream.Close();
            client.Close();
        }


        public void Initialize()
        {

            //send the initialize signal;
            //want to get army - then normal Update information like hand and asssigned cards in zones
            writer.Write((byte)NetMessages.INITIALIZE);
        }

        public  void SendChat(string message)
        {
            writer.Write((byte)NetMessages.CHAT);
            

            char[] msgArray = message.ToCharArray();
            UInt16 msgSize = Convert.ToUInt16(msgArray.Length);
            if (msgSize < 10)
                writer.Write("0" + msgSize.ToString());
            else
                writer.Write(msgSize.ToString());
            
            writer.Write(msgArray);
        }

        public string CheckForChat()
        {
            if (incomingMsgComplete)
            {
                string returnChat = incomingChat;
                incomingChat = "";
                incomingMsgComplete = false;
                return returnChat;
            }
            else
                return null;
        }

        public void Disconnect()
        {
            
            
            serverConnectionState = ServerConnectionState.DISCONNECTED;
        }

        public void Update(int handLocation, int zoneMovedTo)
        {
            ChangesRead = true;
            writer.Write((byte)NetMessages.UPDATE);
            char handOrigin = (char)(handLocation + 48);
            char zoneDest = (char)(zoneMovedTo + 48);
            writer.Write(handOrigin);
            writer.Write(zoneDest);
        }
        public void UpdateComplete()
        {
            writer.Write((byte)NetMessages.UPDATE_COMPLETE);
            
        }
    }
}
